﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace SimplePipeHelper.Common
{
    internal class MessageHelper : IDisposable
    {
        private Action<byte[]> _onMessage;
        private readonly Queue<byte[]> _msgQueue = new Queue<byte[]>();
        private readonly Semaphore _msgSemaphore = new Semaphore(0, int.MaxValue);

        private Thread _threadWorker;
        private bool _threadWorking;
        private readonly object _threadWorkingLockHelper = new object();

        private bool IsThreadWorking
        {
            get
            {
                bool ret;
                lock (_threadWorkingLockHelper)
                {
                    ret = _threadWorking;
                }

                return ret;
            }
            set
            {
                lock (_threadWorkingLockHelper)
                {
                    _threadWorking = value;
                }
            }
        }

        public void Start(Action<byte[]> onMessage)
        {
            if (onMessage == null)
            {
                return;
            }

            _onMessage = onMessage;

            IsThreadWorking = true;
            _threadWorker = new Thread(DoWork)
            {
                IsBackground = true
            };
            _threadWorker.Start();
        }

        public void Stop()
        {
            IsThreadWorking = false;
            _threadWorker?.Join();
            _threadWorker = null;

            if (HasMessage())
            {
                ClearMessage();
            }

            _onMessage = null;
        }

        #region 消息队列操作

        public void AddMessage(byte[] msg)
        {
            if (!IsThreadWorking)
            {
                return;
            }

            lock (_msgQueue)
            {
                _msgQueue.Enqueue(msg);
                _msgSemaphore.Release();
            }
        }

        private bool HasMessage()
        {
            bool ret;
            lock (_msgQueue)
            {
                ret = _msgQueue.Any();
            }

            return ret;
        }

        private byte[] PickMessage()
        {
            byte[] msg = null;
            lock (_msgQueue)
            {
                if (_msgQueue.Count > 0)
                {
                    msg = _msgQueue.Peek();
                    _msgQueue.Dequeue();
                }
            }

            return msg;
        }

        private void ClearMessage()
        {
            lock (_msgQueue)
            {
                _msgQueue.Clear();
            }
        }

        #endregion

        /// <summary>
        /// 线程执行方法
        /// </summary>
        private void DoWork()
        {
            while (IsThreadWorking)
            {
                if (!_msgSemaphore.WaitOne(1))
                {
                    continue;
                }

                var msg = PickMessage();
                _onMessage?.Invoke(msg);
            }
        }

        #region IDisposable Support

        //检测冗余调用
        private bool _disposedValue;

        private void Dispose(bool disposing)
        {
            if (!_disposedValue)
            {
                if (disposing)
                {
                    //释放托管状态(托管对象)。
                }

                //释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                //将大型字段设置为 null。
                Stop();

                _disposedValue = true;
            }
        }

        ~MessageHelper()
        {
            Dispose(false);
        }

        // 添加此代码以正确实现可处置模式。
        void IDisposable.Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
